package com.siyoumi.app.sys.service.payorder;

import com.siyoumi.app.entity.SysOrder;
import com.siyoumi.app.entity.SysRefundOrder;
import com.siyoumi.app.modules.app_book.service.PayOrderBook;
import com.siyoumi.app.modules.fun.service.SvcFun;
import com.siyoumi.app.modules.mall2.service.PayOrderM2;
import com.siyoumi.app.modules.money.service.PayOrderMoney;
import com.siyoumi.app.sys.entity.EnumSysOrder;
import com.siyoumi.app.sys.service.IPayOrder;
import com.siyoumi.app.sys.service.wxapi.WxApiPay;
import com.siyoumi.app.service.SysOrderService;
import com.siyoumi.app.service.SysRefundOrderService;
import com.siyoumi.component.XApp;
import com.siyoumi.component.http.XHttpContext;
import com.siyoumi.config.SysConfig;
import com.siyoumi.entity.SysAccsuperConfig;
import com.siyoumi.exception.EnumSys;
import com.siyoumi.exception.XException;
import com.siyoumi.mybatispuls.JoinWrapperPlus;
import com.siyoumi.service.SysAccsuperConfigService;
import com.siyoumi.util.XDate;
import com.siyoumi.util.XReturn;
import com.siyoumi.util.XStr;
import com.siyoumi.validator.XValidator;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;

@Slf4j
public class PayOrder
        implements IPayOrder {
    static public IPayOrder getIns(SysOrder entity) {
        IPayOrder app = null;

        String appId = entity.getOrder_app_id();
        log.debug("order appId: {}", appId);
        switch (appId) {
            case "m2":
                app = new PayOrderM2();
                break;
            case "app_book":
                app = new PayOrderBook();
                break;
            case "money":
                app = new PayOrderMoney();
                break;
            default:
                XValidator.err(EnumSys.ERR_VAL.getR("订单异常，" + appId));
        }

        app.setEntity(entity);
        return app;
    }

    @SneakyThrows
    static public IPayOrder getBean(SysOrder entity) {
        IPayOrder app = new PayOrder();
        app.setEntity(entity);

        return app;
    }

    /**
     * 立刻处理用户过期订单（考虑使用场景）
     *
     * @param uid
     * @param appId 应用ID
     */
    static public XReturn payExpireHandleByOpenid(String uid, String appId) {
        JoinWrapperPlus<SysOrder> query = SysOrderService.getBean().join();
        query.eq("order_app_id", appId)
                .eq("order_uid", uid)
                .ne("order_pay_ok", 1)
                .eq("order_pay_expire_handle", 0)
                .orderByAsc("order_update_date");
        List<SysOrder> listOrder = SysOrderService.getBean().get(query);
        for (SysOrder entityOrder : listOrder) {
            IPayOrder svcOrder = PayOrder.getIns(entityOrder);
            svcOrder.rollback();
        }

        return XReturn.getR(0);
    }

    public SysOrder getEntity() {
        return XHttpContext.get(KEY);
    }

    public WxApiPay getApiPay() {
        return XHttpContext.getAndSetData(KEY_CONFIG, key -> {
            SysAccsuperConfigService appConfig = SysAccsuperConfigService.getBean();
            SysAccsuperConfig entityConfig = appConfig.getXConfig(getEntity().getX(), true);

            return WxApiPay.getIns(entityConfig);
        });
    }

    public String getX() {
        return getEntity().getX();
    }


    /**
     * 支付前
     */
    public XReturn payBefore(String code) {
        return XReturn.getR(0);
    }

    @Override
    public XReturn pay(String code) {
        XReturn r = orderCheck(false);
        if (r.err()) {
            return r;
        }

        r = payBefore(code);
        if (r.err()) {
            return r;
        }

        return payHandle(code);
    }

    /**
     * 支付
     *
     * @param code
     */
    @SneakyThrows
    public XReturn payHandle(String code) {
        SysOrder entity = getEntity();
        if (entity.checkPayOk()) {
            return EnumSysOrder.PAY.getR();
        }

        if (entity.getOrder_pay_price().compareTo(new BigDecimal("0")) <= 0) {
            throw new XException("订单金额异常：0");
        }

        WxApiPay apiPay = getApiPay();
        long priceFee = XApp.decimalToFee(entity.getOrder_pay_price()); //分
        XReturn r = apiPay.order(entity.getOrder_id()
                , priceFee
                , entity.getOrder_desc()
                , entity.getOrder_openid());
        if (r.err()) {
            return r;
        }

        String prepayId = r.getData("prepay_id", "");
        //拉起支付-参数
        r.setData("api_pay_json", apiPay.getJsApiData(prepayId));

        return r;
    }


    /**
     * 订单检查
     */
    protected XReturn orderCheck(Boolean passExpire) {
        if (getEntity().checkCancel()) {
            return EnumSysOrder.CANCEL.getR();
        }
        if (getEntity().checkPayOk()) {
            return EnumSysOrder.PAY.getR();
        }
        if (!passExpire) {
            if (getEntity().isExpire()) {
                return EnumSysOrder.EXPIRE.getR();
            }
        }

        return XReturn.getR(0);
    }

    @Override
    public XReturn payChoose(String code) {
        return null;
    }

    @Override
    public XReturn payCheck() {
        XReturn r = orderCheck(true);
        if (r.err()) {
            return r;
        }

        WxApiPay apiPay = getApiPay();
        r = apiPay.orderInfo(getEntity().getOrder_id(), null);
        if (r.err()) {
            return r;
        }
        Boolean payOk = apiPay.isPayOk(r);
        if (!payOk) {
            return EnumSysOrder.UNPAY.getR();
        }

        orderSetPayOk(r);
        r.setData("entity_payorder", getEntity());

        return r;
    }

    /**
     * 设置支付成功
     *
     * @param r
     */
    protected void orderSetPayOk(XReturn r) {
        SysOrderService appOrder = SysOrderService.getBean();
        SysOrder entity = appOrder.getEntityLock(getEntity().getKey());

        WxApiPay apiPay = getApiPay();

        String orderWxId = apiPay.orderWxId(r);
        String payDataStr = r.getData("success_time", "");
        LocalDateTime payOkDate = LocalDateTime.parse(payDataStr, XDate.DATE_TIME_ISO_FORMATTER);

        SysOrder update = new SysOrder();
        update.setOrder_id(entity.getOrder_id());
        update.setOrder_pay_ok(1);
        update.setOrder_order_id_ex(orderWxId);
        update.setOrder_pay_ok_date(payOkDate);

        XApp.getTransaction().execute(status -> {
            return appOrder.updateById(update);
        });
    }

    @Override
    public XReturn rollback() {
        //应用自行封装
        XValidator.err(50233, "未开发");
        return null;
    }

    @Override
    public XReturn cancel() {
        if (getEntity().checkCancel()) {
            return EnumSysOrder.CANCEL.getR();
        }
        if (getEntity().checkPayOk()) {
            return EnumSysOrder.PAY.getR();
        }

        SysOrderService appOrder = SysOrderService.getBean();
        SysOrder entity = appOrder.getEntityLock(getEntity().getKey());

        SysOrder update = new SysOrder();
        update.setOrder_del(XDate.toS());
        update.setOrder_id(entity.getOrder_id());
        appOrder.updateById(update);

        return XReturn.getR(0);
    }

    /**
     * 申请退款
     *
     * @param refundId
     * @param refundPrice
     * @param desc
     */
    public XReturn refundApply(String refundId, BigDecimal refundPrice, String desc) {
        if (!getEntity().checkPayOk()) {
            return EnumSysOrder.UNPAY.getR();
        }

        if (refundPrice.compareTo(getEntity().getOrder_pay_price()) > 0) {
            return XReturn.getR(20080, "退款金额大于原订单金额");
        }

        SysOrderService appOrder = SysOrderService.getBean();
        SysOrder entity = appOrder.getEntityLock(getEntity().getKey());
        if (entity.getOrder_refund() > 0) {
            return EnumSysOrder.REFUND_APPLY.getR();
        }

        SysRefundOrder entityRefund = new SysRefundOrder();
        entityRefund.setRefo_order_id(getEntity().getOrder_id());
        entityRefund.setRefo_id_src(getEntity().getOrder_id());
        entityRefund.setRefo_openid(getEntity().getOrder_uid());
        entityRefund.setRefo_refund_id(refundId);
        entityRefund.setRefo_refund_price(refundPrice);
        entityRefund.setRefo_apply_desc(desc);
        entityRefund.setRefo_x_id(getX());
        SysRefundOrderService.getBean().save(entityRefund);

        log.info("支付订单状态改为退款中");
        SysOrder updateOrder = new SysOrder();
        updateOrder.setOrder_id(getEntity().getOrder_id());
        updateOrder.setOrder_refund(XDate.toS().intValue());
        appOrder.updateById(updateOrder);


        return XReturn.getR(0);
    }

    @Override
    public XReturn refund(String refundId) {
        SysRefundOrderService appRefOrder = SysRefundOrderService.getBean();
        SysRefundOrder entityRefund = appRefOrder.getEntityByOrderId(getEntity().getOrder_id(), refundId);
        if (entityRefund == null) {
            return EnumSys.ERR_VAL.getR("退款订单异常");
        }
        if (entityRefund.getRefo_apply_status() != 1) {
            return XReturn.getR(20263, "退款订单未审核");
        }
        if (entityRefund.getRefo_refund_errcode() != 0) {
            return EnumSysOrder.REFUND.getR();
        }

        XReturn r;
        if (getEntity().getOrder_pay_type() == 1) {
            log.info("积分商品退积分");
            String key = "refund|" + entityRefund.getRefo_refund_id();
            SvcFun.getBean().add(key
                    , entityRefund.getRefo_openid()
                    , entityRefund.getKey()
                    , getEntity().getOrder_app_id()
                    , entityRefund.getRefo_refund_price().intValue()
                    , entityRefund.getRefo_apply_desc());
            r = XReturn.getR(0, XStr.concat("成功[", XHttpContext.getXConfig().getAconfig_fun_name(), "支付]"));
        } else {
            if (getEntity().getOrder_use_money() == 1L) {
                r = XReturn.getR(0, XStr.concat("成功[余额支付]"));
            } else {
                WxApiPay pay = WxApiPay.getIns();

                Long orderFee = getEntity().getOrder_pay_price().longValue();
                Long refundFee = entityRefund.getRefo_refund_price().longValue();
                r = pay.orderRefund(getEntity().getOrder_id()
                        , entityRefund.getRefo_refund_id()
                        , orderFee
                        , refundFee);
                if (SysConfig.getIns().isDev()) {
                    r = XReturn.getR(0, "OK");
                }
            }
        }


        return r;
    }
}
